package com.mask.im.sdk.service.impl;

import com.alibaba.fastjson.JSON;
import com.mask.im.sdk.dto.IMPushMessage;
import com.mask.im.sdk.service.MessagePushService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

/**
 * 简单的消息服务中间件
 * 只负责发送消息到对应的节点监听器
 *
 * @author jian
 */
@Slf4j
@Service
public class MessagePushServiceImpl implements MessagePushService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // Redis Key前缀
    // im:user:node:{userId}:{device} -> nodeId
    private static final String USER_NODE_PREFIX = "im:user:node:";
    // im:msg:queue:{nodeId} -> messageList
    private static final String MESSAGE_QUEUE_PREFIX = "im:msg:queue:";
    // im:group:members:{groupId} -> Set<userId>
    private static final String GROUP_MEMBERS_PREFIX = "im:group:members:";


    @Override
    public <T> Boolean pushMessage(IMPushMessage<T> message) {
        if (message == null || message.getReceiverId() == null) {
            throw new IllegalArgumentException("消息或接收者ID不能为null");
        }

        if ("FRIEND".equals(message.getPushType())) {
            // 根据接收者ID查找对应的节点
            String nodeId = getUserNode(message.getReceiverId());

            if (nodeId == null) {
                log.warn("用户 {} 不在线，无法发送消息", message.getReceiverId());
                return null;
            }
            // 推送到对应节点的队列
            String queueName = MESSAGE_QUEUE_PREFIX + nodeId;
            String jsonMsg = JSON.toJSONString(message);
            redisTemplate.opsForList().leftPush(queueName, jsonMsg);
            log.info("【消息推送】发送者: {}, 接收者: {}, 目标节点: {}, 队列: {}, 消息类型: {}", 
                    message.getSenderId(), message.getReceiverId(), nodeId, queueName, message.getPushType());
        } else if ("GROUP".equals(message.getPushType())) {
            sendGroupMessage(message, message.getGroupId());
        }
        return true;
    }

    @Override
    public <T> List<Long> pushGroupMessage(IMPushMessage<T> pushMessage) {
        return null;
    }

    @Override
    public Boolean isOnline(Long userId) {
        String userNode = getUserNode(userId);
        return StringUtils.isNotBlank(userNode);
    }

    @Override
    public Boolean isOnline(Long userId, String device) {
        String userNode = getUserNode(userId, device);
        return StringUtils.isNotBlank(userNode);
    }

    @Override
    public List<Long> getAllOnlineUser() {
        return null;
    }


    /**
     * 注册用户到节点
     *
     * @param userId 用户ID
     * @param device 设备类型
     * @param nodeId 节点ID
     */
    public void registerUser(String userId, String device, String nodeId) {
        String key = USER_NODE_PREFIX + userId + ":" + device;
        redisTemplate.opsForValue().set(key, nodeId);
        log.info("用户 {} 设备 {} 已注册到节点 {}", userId, device, nodeId);
    }

    /**
     * 注销用户
     *
     * @param userId 用户ID
     * @param device 设备类型
     */
    public void unregisterUser(String userId, String device) {
        String key = USER_NODE_PREFIX + userId + ":" + device;
        redisTemplate.delete(key);
        log.info("用户 {} 设备 {} 已注销", userId, device);
    }

    /**
     * 根据用户ID查找节点（默认设备）
     *
     * @param userId 用户ID
     * @return 节点ID
     */
    private String getUserNode(Long userId) {
        // 先尝试查找默认设备
        String key = USER_NODE_PREFIX + userId + ":default";
        Object nodeId = redisTemplate.opsForValue().get(key);
        if (nodeId != null) {
            return nodeId.toString();
        }
        // 如果没找到，查找所有设备
        String pattern = USER_NODE_PREFIX + userId + ":*";
        java.util.Set<String> keys = redisTemplate.keys(pattern);
        if (keys != null && !keys.isEmpty()) {
            Object firstNodeId = redisTemplate.opsForValue().get(keys.iterator().next());
            if (firstNodeId != null) {
                return firstNodeId.toString();
            }
        }

        return null;
    }

    /**
     * 根据用户ID和设备查找节点
     *
     * @param userId 用户ID
     * @param device 设备类型
     * @return 节点ID
     */
    public String getUserNode(Long userId, String device) {
        String key = USER_NODE_PREFIX + userId + ":" + device;
        Object nodeId = redisTemplate.opsForValue().get(key);
        return nodeId != null ? nodeId.toString() : null;
    }


    /**
     * 直接发送消息到指定节点
     *
     * @param msg    消息对象
     * @param nodeId 目标节点ID
     * @return 消息ID
     */
    public String sendToGroupNode(IMPushMessage msg, String nodeId) {
        if (msg == null || nodeId == null) {
            throw new IllegalArgumentException("消息或节点ID不能为null");
        }
        // 直接推送到指定节点的队列
        String queueName = MESSAGE_QUEUE_PREFIX + nodeId;
        String jsonMsg = JSON.toJSONString(msg);
        redisTemplate.opsForList().leftPush(queueName, jsonMsg);
        log.info("【群组消息推送】发送者: {}, 目标节点: {}, 队列: {}, 接收者数量: {}", 
                msg.getSenderId(), nodeId, queueName, 
                msg.getReceiversId() != null ? msg.getReceiversId().size() : 0);
        return "0";
    }


    /**
     * 获取所有在线节点
     *
     * @return 在线节点ID列表
     */
    public java.util.List<String> getOnlineNodes() {
        String pattern = MESSAGE_QUEUE_PREFIX + "*";
        java.util.Set<String> keys = redisTemplate.keys(pattern);
        if (keys == null || keys.isEmpty()) {
            return new java.util.ArrayList<>();
        }

        java.util.List<String> nodeIds = new java.util.ArrayList<>();
        for (String key : keys) {
            String nodeId = key.substring(MESSAGE_QUEUE_PREFIX.length());
            nodeIds.add(nodeId);
        }

        return nodeIds;
    }

    /**
     * 发送群组消息
     *
     * @param msg     消息对象
     * @param groupId 群组ID
     * @return 消息ID列表
     */
    public java.util.List<String> sendGroupMessage(IMPushMessage msg, Long groupId) {
        if (msg == null || groupId == null) {
            throw new IllegalArgumentException("消息或群组ID不能为null");
        }


        // 获取群组成员
        java.util.Set<Long> groupMembers = getGroupMembers(groupId);


        if (groupMembers == null || groupMembers.isEmpty()) {
            log.warn("群组 {} 没有成员，无法发送消息", groupId);
            return new java.util.ArrayList<>();
        }

        // 按节点分组成员
        java.util.Map<String, java.util.List<Long>> nodeMembersMap = new java.util.HashMap<>();

        java.util.List<Long> offlineMembers = new java.util.ArrayList<>();

        for (Long memberId : groupMembers) {
            String nodeId = getUserNode(memberId);
            if (nodeId != null) {
                nodeMembersMap.computeIfAbsent(nodeId, k -> new java.util.ArrayList<>()).add(memberId);
            } else {
                offlineMembers.add(memberId);
            }
        }

        // 发送到各个节点
        java.util.List<String> messageIds = new java.util.ArrayList<>();
        for (java.util.Map.Entry<String, java.util.List<Long>> entry : nodeMembersMap.entrySet()) {

            String nodeId = entry.getKey();
            java.util.List<Long> members = entry.getValue();
            // 为每个节点创建消息副本
            IMPushMessage nodeMsg = createGroupMessageForNode(msg, groupId, members);
            String messageId = sendToGroupNode(nodeMsg, nodeId);
            if (messageId != null) {
                messageIds.add(messageId);
            }
        }

        log.info("群组消息已发送到 {} 个节点，成功发送 {} 条，离线成员 {} 个",
                nodeMembersMap.size(), messageIds.size(), offlineMembers.size());

        return messageIds;
    }

    /**
     * 为节点创建群组消息副本
     */
    private IMPushMessage createGroupMessageForNode(IMPushMessage pushMessage, Long groupId, java.util.List<Long> members) {
        IMPushMessage message = new IMPushMessage();
        message.setSenderId(pushMessage.getSenderId());
        message.setReceiverId(pushMessage.getReceiverId());
        message.setReceiversId(members);
        message.setContent(pushMessage.getContent());
        message.setPushType("GROUP");
        return message;
    }

    /**
     * 添加群组成员
     *
     * @param groupId 群组ID
     * @param userId  用户ID
     */
    public void addGroupMember(String groupId, String userId) {
        String key = GROUP_MEMBERS_PREFIX + groupId;
        redisTemplate.opsForSet().add(key, userId);
        log.info("用户 {} 已加入群组 {}", userId, groupId);
    }

    /**
     * 移除群组成员
     *
     * @param groupId 群组ID
     * @param userId  用户ID
     */
    public void removeGroupMember(String groupId, String userId) {
        String key = GROUP_MEMBERS_PREFIX + groupId;
        redisTemplate.opsForSet().remove(key, userId);
        log.info("用户 {} 已退出群组 {}", userId, groupId);
    }

    /**
     * 批量添加群组成员
     *
     * @param groupId 群组ID
     * @param userIds 用户ID列表
     */
    public void addGroupMembers(String groupId, java.util.List<String> userIds) {
        if (userIds == null || userIds.isEmpty()) {
            return;
        }

        String key = GROUP_MEMBERS_PREFIX + groupId;
        redisTemplate.opsForSet().add(key, userIds.toArray());
        log.info("已批量添加 {} 个用户到群组 {}", userIds.size(), groupId);
    }

    /**
     * 获取群组成员
     *
     * @param groupId 群组ID
     * @return 群组成员ID集合
     */
    public java.util.Set<Long> getGroupMembers(Long groupId) {
        String key = GROUP_MEMBERS_PREFIX + groupId;
        java.util.Set<Object> members = redisTemplate.opsForSet().members(key);
        if (members == null) {
            return new java.util.HashSet<>();
        }

        java.util.Set<Long> stringMembers = new java.util.HashSet<>();
        for (Object member : members) {
            if (member != null) {
                stringMembers.add(Long.valueOf(member.toString()));
            }
        }
        return stringMembers;
    }

    /**
     * 获取群组成员数量
     *
     * @param groupId 群组ID
     * @return 成员数量
     */
    public Long getGroupMemberCount(String groupId) {
        String key = GROUP_MEMBERS_PREFIX + groupId;
        return redisTemplate.opsForSet().size(key);
    }

    /**
     * 检查用户是否在群组中
     *
     * @param groupId 群组ID
     * @param userId  用户ID
     * @return 是否在群组中
     */
    public boolean isGroupMember(String groupId, String userId) {
        String key = GROUP_MEMBERS_PREFIX + groupId;
        return Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(key, userId));
    }

    /**
     * 删除群组
     *
     * @param groupId 群组ID
     */
    public void deleteGroup(String groupId) {
        String key = GROUP_MEMBERS_PREFIX + groupId;
        redisTemplate.delete(key);
        log.info("群组 {} 已删除", groupId);
    }
}
